package com.ipay.wechat.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.ipay.common.Base64Coder;
import com.ipay.core.HttpRequest;
import com.ipay.entity.SysConfigEntity;
import com.ipay.foreign.pojo.MerchantPayParameter;
import com.ipay.foreign.service.MerchantPayParameterService;
import com.ipay.wechat.pojo.*;
import com.ipay.wechat.service.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.ipay.annotation.IgnoreAuth;
import com.ipay.core.HttpGateway;
import com.ipay.core.Param;
import com.ipay.entity.BizSequenceType;
import com.ipay.entity.PaymentEntity;
import com.ipay.service.ApiPayService;
import com.ipay.service.impl.DefaultSequenceManager;
import com.ipay.utils.Constant;
import com.ipay.utils.HttpClientUtils;
import com.ipay.utils.IPUtils;
import com.ipay.utils.MD5;
import com.ipay.utils.MapUtils;
import com.ipay.utils.PageUtils;
import com.ipay.utils.Query;
import com.ipay.utils.R;
import com.ipay.utils.RandomStringUtils;
import com.ipay.utils.StringUtil;
import com.ipay.utils.XmlUtil;
import com.ipay.wechat.component.Wechat;
import com.ipay.wechat.interceptor.Token;
import com.ipay.wechat.util.Utils;

/**
 * 支付交易订单流水（支付、退款）
 *
 * @author hacken
 * @email hacken_hu@163.com
 * @date 2017-06-13 20:11:53
 */
@Controller
@RequestMapping("payorder")
public class PayorderController {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private PayorderService payorderService;
    @Autowired
    private MerchantInfoService merchantService;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private HttpGateway gateway;
    @Autowired
    private Wechat wechat;
    @Autowired
    private LoginService loginService;
    @Autowired
    private PayChannelService payChannelService;
    @Autowired
    private TradeRecordService tradeRecordService;
    @Autowired
    private UserWechatInfoService uwiService;
    @Autowired
    private MerchantPayParameterService merchantPayParameterService;


    /**
     * 信息
     * payorder/infoPabcsPay
     */
    @RequestMapping("/infoPabcsPay")
    public R infoPabcsPay() {
        PayorderEntity payorder=new PayorderEntity();
        PayChannelEntity payChannel=new PayChannelEntity();
        payChannel.setPayChannelNo("7a217a35254469ecb69f8d7161b0f611");
        payChannel.setPayKey("2b125c12e7f2de366dc376b4d330bd01");
        payorderService.paylist(payorder, payChannel);
        return R.ok();
    }

    /**
     * 保存本系统订单
     * Busid 商户ID
     */
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    @ResponseBody
    @IgnoreAuth
    public R save(@RequestBody PayorderEntity payorder) throws Exception {
        if (StringUtil.isBlank(payorder.getBusid()) || StringUtil.isBlank(payorder.getResource())) {
            return R.error("支付请求数据错误");
        }
        Object openid = request.getSession().getAttribute("openid");//微信或支付宝唯一标示
        logger.info("======微信或支付宝唯一标示=====:" + openid);
        if (StringUtil.isEmpty(openid)) {
            return R.error("请用微信或支付宝扫码支付");
        }
        logger.info("getBusid()=======:" + payorder.getBusid() + "===getResource()=======:" + payorder.getResource() + "-------payremark=" + payorder.getPayremark() + "-------openid=" + payorder.getOpenid());
        MerchantInfoEntity merchant = merchantService.queryObject(payorder.getBusid());//商户资料
        if (merchant == null || StringUtil.isEmpty(merchant.getMerchantNo()) || StringUtil.isEmpty(merchant.getPayKey())) {
            logger.info("检查payKey是否包含");
            return R.error("商户资料获取失败");
        }
        payorder.setLaunchMode(Constant.LAUNCHMODE_GZH);//发起方式（0公众号；1扫码支付；3刷卡支付;4第三方pc端,5固定金额扫码支付，6第三方web）
        if (StringUtil.isNotEmpty(payorder.getPayType()) && payorder.getPayType().equals("1")) { //1区分第三方还是  0二维码发起支付 2还是固定金额二维码发起支付
            MerchantPayParameter merchantPayParameter = merchantPayParameterService.queryObject(payorder.getPayId());
            if (merchantPayParameter == null || StringUtil.isEmpty(merchantPayParameter.getMerchantNo())) {
                return R.error("参数错误");
            }
            Map<String, String> map = new HashMap<String, String>();
            map.put("merchantNo", merchant.getMerchantNo());
            map.put("codeNo", payorder.getCodeNo());
            map.put("sponsorOrderNo", payorder.getSponsorOrderNo());
            map.put("payMoney", payorder.getPayMoney());
            String payremarkEncode = URLEncoder.encode(payorder.getPayremark(), "utf-8");///订单说明
            map.put("payremark", payremarkEncode);
            map.put("callbackUrl", merchantPayParameter.getCallbackUrl());
            map.put("notifyUrl", payorder.getNotifyUrl());
            logger.info("加密参数=====:" + merchant.getMerchantNo() + "===:" + payorder.getCodeNo() + "===:" +
                    payorder.getSponsorOrderNo() + "===:" + payorder.getPayMoney() + "===:" + payremarkEncode + "===:" + payorder.getNotifyUrl() + "===:" + payorder.getSign());
            String strtosign = MapUtils.formatUrlMap(map, false, false);
            //TODO 查询商户相关数据  =payKey
            String parameter = Base64Coder.encode(strtosign);
            String signstr = MD5.sign(parameter, "&payKey=" + merchant.getPayKey(), "utf-8");
            if (!signstr.equals(payorder.getSign())) {
                return R.error("签名错误");
            }
            payorder.setLaunchMode(Constant.LAUNCHMODE_DSF_PC);//发起方式（0公众号；1扫码支付；3刷卡支付;4第三方pc端,5固定金额扫码支付，6第三方web）
            payorder.setBody(merchantPayParameter.getPayremark());
        } else if (StringUtil.isNotEmpty(payorder.getPayType()) && payorder.getPayType().equals("2")) { //1区分第三方还是  0二维码发起支付 2还是固定金额二维码发起支付
            MerchantPayParameter merchantPayParameter = merchantPayParameterService.queryObject(payorder.getPayId());
            if (merchantPayParameter == null || StringUtil.isEmpty(merchantPayParameter.getMerchantNo())
                    ||StringUtil.isEmpty(merchantPayParameter.getCodeNo())) {
                return R.error("参数错误");
            }else{
                if(!payorder.getCodeNo().equals(merchantPayParameter.getCodeNo())) {  ///支付  收款员编号与查询的参数里的收款员编号是否相符){
                    return R.error("参数错误");
                }
                if(payorder.getAmount().compareTo(merchantPayParameter.getPayMoney()) != 0){//结果是:-1 小于,0 等于,1 大于
                    return R.error("参数错误");
                }
            }
            payorder.setLaunchMode(Constant.LAUNCHMODE_DSF_GJSMZF);//发起方式（0公众号；1扫码支付；3刷卡支付;4第三方pc端or第三方web,5固定金额扫码支付，6）
            payorder.setBody(merchantPayParameter.getPayremark());
        }else{
            payorder.setBody("扫 "+merchant.getShopName()+" 收款员("+payorder.getCodeNo()+")二维码支付订单");
        }
        payorder.setRecordno(DefaultSequenceManager.get().next(BizSequenceType.TRANSQ));//订单号
        payorder.setOrderdate(new Date());
        payorder.setTimeoutdate(new Date(System.currentTimeMillis() + 300000));// 订单超时5分钟
        payorder.setWxOpenid(String.valueOf(openid));
        payorder.setOpenid(String.valueOf(openid));
        payorder.setPayResult(Constant.PAY_RESULT_ERROR);
        payorder.setMchCreateIp(IPUtils.getIpAddr(request));//
        // 支付接口地址
        try {
            //查询支付信息
            Map<String, Object> mapPayChannel = new HashMap<String, Object>();
            mapPayChannel.put("merchantNo", payorder.getBusid());
            mapPayChannel.put("payState", Constant.Status.ENABLE.getValue());//状态 0、删除 1、启用 2、禁用
            if (payorder.getResource() != null && payorder.getResource().equals("0")) {//获取：来源（0 微信、1 支付宝）
                mapPayChannel.put("payType", Constant.PayType.PAY_WX.getValue());
            } else if (payorder.getResource() != null && payorder.getResource().equals("1")) {
                mapPayChannel.put("payType", Constant.PayType.PAY_ZFB.getValue());
            } else {
                return R.error("支付来源错误");
            }
            PayChannelEntity payChannel = payChannelService.queryPayBymerchantNo(mapPayChannel);
            if (payChannel == null || StringUtil.isEmpty(payChannel.getPayChannelNo()) || StringUtil.isEmpty(payChannel.getPayRate()) || StringUtil.isEmpty(payChannel.getPayKey())) {
                return R.error("商户渠道参数错误");
            } else {
                //单笔累计限额
                if (StringUtil.isNotEmpty(payChannel.getMaxTransactionMoney())) {
                    if (payorder.getAmount().compareTo(payChannel.getMaxTransactionMoney()) == 1) { //结果是:-1 小于,0 等于,1 大于
                        return R.error("已超出商户号设置的最大限额【" + payChannel.getMaxTransactionMoney() + "】");
                    }
                }
            }
            /*//日累计限额
            //查询当前商户渠道已累计退/收款金额
            Map<String, Object> payMap = new HashMap<>();
            payMap.put("busId", payorder.getBusid());
            payMap.put("paychannelId", payChannel.getPayChannelId());
            BigDecimal sumPayorder = payorderService.findTdSumAmountByPayChannelId(payMap);
            if (sumPayorder != null && StringUtil.isNotEmpty(sumPayorder)) {
                if (sumPayorder.compareTo(payChannel.getDayMaxMoney()) != -1) { //【日累计限额（元/笔）】结果是:-1 小于,0 等于,1 大于
                    return R.error("已超出商户号设置的日累计限额【" + payChannel.getDayMaxMoney() + "】");
                }
            }*/
            //签约汇率
            payorder.setPayRate(payChannel.getPayRate());
            //结算金额  金额*签约汇率/100
            BigDecimal serviceCharge = payChannel.getPayRate().multiply(payorder.getAmount()).divide(BigDecimal.valueOf(100));
            payorder.setServiceCharge(serviceCharge);
            BigDecimal settlementAmount = payorder.getAmount().subtract(serviceCharge);
            payorder.setSettlementAmount(settlementAmount);
            payorder.setPaychannelId(payChannel.getPayChannelId());//支付渠道id
            // 1、生成本系统中订单
            return payorderService.savePayOrder(payorder, payChannel);
        } catch (Exception e) {
            logger.error("请求支付接口异常：", e);
            // 异常记录
            payorder.setRemark("请求支付接口异常");
            payorder.setStatus(Constant.STATUS_ERROR);
            payorderService.update(payorder);
            return R.error(payorder.getRemark());
        }
    }

    /**
     * 交易状态通知
     *
     * @return
     * @throws UnsupportedEncodingException
     */
    @IgnoreAuth
    @PostMapping("/jspayNotify")
    public R jsPayNotify(HttpServletRequest req) throws UnsupportedEncodingException {
        req.setCharacterEncoding("utf-8");
        String resultmap = XmlUtil.parseRequst(req);
        logger.info("====================交易状态通知==================================payresult");
        logger.info("==========payresult----" + resultmap);
        logger.info("====================交易状态通知==================================payresult");
        if (StringUtil.isNotEmpty(resultmap)) {
            Map<String, Object> map = new HashMap<String, Object>();
            try {
                map = XmlUtil.xmlStr2Map(resultmap);
            } catch (Exception e) {
                logger.error("支付回调异常", e);
            }
            Object status = map.get("status");
            logger.info("====================交易状态通知====status==============================" + status);
            if (StringUtil.isNotEmpty(status) && "0".equals(status)) {
                Object result_code = map.get("result_code");
                logger.info("====================交易状态通知====result_code==============================" + result_code);
                if (StringUtil.isNotEmpty(result_code) && "0".equals(result_code)) {
                    // 此处可以在添加相关处理业务，校验通知参数中的商户订单号out_trade_no和金额total_fee是否和商户业务系统的单号和金额是否一致，一致后方可更新数据库表中的记录。
                    String orderNo = map.get("out_trade_no").toString();
                    BigDecimal total_fee = new BigDecimal(map.get("total_fee").toString());
                    PayorderEntity order = payorderService.queryByOderNo(orderNo);//D2017092109000000091
                    if (order != null) {
                        logger.info("======================Pay_result============" + orderNo + "  =  " + order.getPayResult());
                        if (StringUtil.isNotEmpty(order.getPayResult()) && order.getPayResult().intValue() == 0) {
                            //******网第三方推送信息
                            if (StringUtil.isNotEmpty(order.getLaunchMode()) && Constant.LAUNCHMODE_DSF_PC.equals(order.getLaunchMode())) {  //4第三方pc端
                                callbackNotify(order, total_fee);
                            }
                            return R.ok("success");
                        } else if (order.getAmount().compareTo(total_fee.divide(BigDecimal.valueOf(100))) == 0) {  //结果是:-1 小于,0 等于,1 大于
                            logger.info("======================Amount============" + order.getAmount() + "===============" + total_fee);
                            order.setPayResult(Integer.valueOf(map.get("pay_result").toString()));//支付结果：0—成功；其它—失败
                            order.setTransactionId(map.get("transaction_id").toString());
                            order.setTimeEnd(map.get("time_end").toString());
                            order.setBankType(map.get("bank_type").toString());
                            order.setOpenid(map.get("openid").toString());
                            if ("0".equals(map.get("pay_result").toString())) {
                                order.setStatus(Constant.STATUS_YZF);
                            } else {
                                order.setRemark(map.get("pay_info").toString());//支付结果信息，支付成功时为空
                            }
                            TPayresultEntity entity = initPayResultNotify(map);
                            payorderService.update(order, entity);// 更新订单状态
                            if (Constant.STATUS_YZF.equals(order.getStatus())) {
                                //微信信息推送
                                pushMessage(order.getBusid(), order.getCodeNo(), order.getAmount().toString(), order.getResource(), order.getRecordno(), order.getOrderdate());
                                //******网第三方推送信息
                                if (StringUtil.isNotEmpty(order.getLaunchMode()) && Constant.LAUNCHMODE_DSF_PC.equals(order.getLaunchMode())) {  //4第三方pc端
                                    callbackNotify(order, total_fee);
                                }
                            }

                            if (StringUtil.isNotEmpty(order.getResource()) && Constant.Resource.RESOURCE_WX.getValue().equals(order.getResource())) { ///只有是微信支付才获取微信用户信息
                                UserWechatInfo userWechatInfo = uwiService.gainUserWechatInfo(order.getWxOpenid());//获得微信信息
                                if (userWechatInfo != null && StringUtil.isNotEmpty(userWechatInfo.getOpenid())) {
                                    UserWechatInfo wechat = uwiService.findOneByOpenidInUserWX(order.getWxOpenid());
                                    if (wechat != null && StringUtil.isNotEmpty(wechat.getOpenid())) {
                                        uwiService.updateWechatUserInfo(userWechatInfo);
                                    } else {
                                        uwiService.addWechatUserInfo(userWechatInfo);
                                    }
                                }
                            }
                            return R.ok("success");
                        }
                    }
                }
            }
        }
        return R.ok("fail");
    }


    /**
     * 微信信息推送处理
     *
     * @param merchantId //商户编号
     * @param amount     //金额
     * @param resource   //获取：来源（0 微信、1 支付宝）
     * @param recordno   //订单号
     * @param orderdate  //订单创建时间
     */
    private void pushMessage(String merchantId, String codeNo, String amount, String resource, String recordno, Date orderdate) {
        logger.info("============进入信息推送===收款=============" + merchantId + " - " + amount + " - " + resource + " - " + recordno + " - " + orderdate);
        List<WechatLogin> loginList = loginService.findWechatLoginByMerchantId(merchantId, codeNo);
        for (WechatLogin wechatLogin : loginList) {
            if (wechatLogin != null && StringUtil.isNotEmpty(wechatLogin.getOpenid()) //getOpenid微信openid；
                    && StringUtil.isNotEmpty(wechatLogin.getIsNotify())  //getIsNotify是否通知 0:表示不通知 、1:表示通知
                    && StringUtil.isNotEmpty(wechatLogin.getStatus())) {  //getStatus 状态：0未登陆，1已登录
                if (Constant.ISNOTIFY_TZ.intValue() == wechatLogin.getIsNotify() //是否通知 0:表示不通知 、1:表示通知
                        && Constant.LOGIN_STATUS_YDL.intValue() == wechatLogin.getStatus()) { ///状态：0未登陆，1已登录
                    Map<String, Object> mapMessage = new HashMap<String, Object>();
                    mapMessage.put("openid", wechatLogin.getOpenid());
                    mapMessage.put("sendType", String.valueOf(Constant.SendType.SEND_RECEIVABLES.getValue()));//收款成功通知
                    mapMessage.put("keyword1", amount);//金额
                    mapMessage.put("keyword2", wechatLogin.getShopname());//商家名称
                    mapMessage.put("keyword3", resource);//
                    mapMessage.put("keyword4", recordno);
                    String orderDate = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(orderdate);
                    mapMessage.put("keyword5", orderDate);
                    mapMessage.put("url", wechat.getBaseUrl() + "menu/?action=tradingCenter");//Constant.DOMAINURL_HTTPS
                    tradeRecordService.pushTradeMessage(mapMessage);
                }
            }
        }
    }

    /**
     * 回调第三方
     */
    private void callbackNotify(PayorderEntity order, BigDecimal total_fee) {
        try {
            logger.info("============回调第三方===收款=============");
            //查询支付信息
            MerchantInfoEntity merchant = merchantService.queryObject(order.getBusid());
            if (merchant != null && StringUtil.isNotEmpty(merchant.getMerchantNo()) && StringUtil.isNotEmpty(merchant.getPayKey())) {
                Map<String, String> mapdsfbak = new HashMap<>();
                mapdsfbak.put("status", order.getStatus());//1已支付
                mapdsfbak.put("merchantNo", merchant.getMerchantNo());//商户号
                mapdsfbak.put("sponsorOrderNo", order.getSponsorOrderNo());//发起方订单号
                mapdsfbak.put("resource", order.getResource());//来源（0 微信、1 支付宝）
                mapdsfbak.put("amount", String.valueOf(total_fee));//金额
                mapdsfbak.put("recordNo", order.getRecordno());//商户订单号
                mapdsfbak.put("time_end", order.getTimeEnd());//
                mapdsfbak.put("bank_type", order.getBankType());//
                mapdsfbak.put("openid", order.getOpenid());//
                String strtosign = MapUtils.formatUrlMap(mapdsfbak, false, false);
                //TODO 查询商户相关数据
                String parameter = Base64Coder.encode(strtosign);
                String signstr = MD5.sign(parameter, "&payKey=" + merchant.getPayKey(), "utf-8");
                System.out.println("===第三方回调地址===:" + order.getNotifyUrl());
                String sr = HttpRequest.sendPost(order.getNotifyUrl(), strtosign + "&sign" + signstr);
                System.out.println("===" + sr);
            } else {
                logger.info("********************读取支付渠道商信息错误*************" + order.getBusid());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 退款交易
     * http://www.***.cn/wechat/payorder/refund?merchantNo=88888889
     * 原订单id
     * 订单支付金额
     * 退款订单号
     */
    @RequestMapping(value = "/refund", method = RequestMethod.POST)
    @ResponseBody
    @IgnoreAuth
    @Token(remove = true)
    public R refund(HttpServletRequest request, @RequestBody PayorderEntity payorder) {
        String openid = (String) request.getSession().getAttribute("openid");
        if (StringUtil.isBlank(payorder.getRecordno())) {
            return R.error("退款订单编号不能为空");
        }
        // 原有交易订单
        PayorderEntity oldorder = payorderService.queryObject(payorder.getId());
        //TODO 还的计算之前退款金额
        //结果是-1小于      0等于      1大于
        if (payorder.getAmount().compareTo(oldorder.getAmount()) > 0) {
            return R.error("退款金额不能大于订单总金额");
        }
        if (payorder.getAmount().compareTo(BigDecimal.valueOf(0)) != 1) {
            return R.error("退款金额必须大于0");
        }
        // 构建退款交易
        PayorderEntity refundObj = new PayorderEntity();
        refundObj.setOrderid(oldorder.getRecordno());
        refundObj.setAmount(payorder.getAmount());
        refundObj.setCategory(Constant.CATEGORY_TK);
        refundObj.setRecordno(payorder.getRecordno());//设置：退款订单号
        refundObj.setBusid(oldorder.getBusid());
        refundObj.setOrderdate(new Date());
        refundObj.setResource(oldorder.getResource());
        if (payorder.getAmount().compareTo(oldorder.getAmount()) == 0) {
            refundObj.setRefundtype("1");// 全额退款
        } else {
            refundObj.setRefundtype("0");
        }
        refundObj.setCodeNo(oldorder.getCodeNo());
        refundObj.setStatus(Constant.STATUS_TKSB);
        refundObj.setPayResult(Constant.PAY_RESULT_ERROR);
        refundObj.setMchCreateIp(IPUtils.getIpAddr(request));
        ///查询下商户收款参数信息
        Map<String, Object> mapPayChannel = new HashMap<String, Object>();
        mapPayChannel.put("merchantNo", oldorder.getBusid());
        mapPayChannel.put("payState", Constant.Status.ENABLE.getValue());//状态 0、删除 1、启用 2、禁用
        System.out.println(oldorder.getResource() + "" + (Constant.Resource.RESOURCE_WX.getValue().equals(oldorder.getResource())));
        System.out.println(oldorder.getResource() + "" + (Constant.Resource.RESOURCE_ZFB.getValue().equals(oldorder.getResource())));
        if (oldorder.getResource() != null && Constant.Resource.RESOURCE_WX.getValue().equals(oldorder.getResource())) {//获取：来源（0 微信、1 支付宝）
            mapPayChannel.put("payType", Constant.PayType.PAY_WX.getValue());//微信
        } else if (oldorder.getResource() != null && Constant.Resource.RESOURCE_ZFB.getValue().equals(oldorder.getResource())) {
            mapPayChannel.put("payType", Constant.PayType.PAY_ZFB.getValue());//支付宝
        } else {
            return R.error("商户渠道参数错误");
        }
        PayChannelEntity payChannel = payChannelService.queryPayBymerchantNo(mapPayChannel);
        if (payChannel == null || StringUtil.isEmpty(payChannel.getPayChannelNo()) || StringUtil.isEmpty(payChannel.getPayKey())) {
            return R.error("商户渠道参数错误");
        }
        refundObj.setPaychannelId(payChannel.getPayChannelId());
        Map<String, String> map = new HashMap<String, String>();
        map.put("service", "unified.trade.refund");
        map.put("version", "2.0");
        map.put("charset", "UTF-8");
        map.put("sign_type", "MD5");
        map.put("mch_id", payChannel.getPayChannelNo());
        //商户订单号  -TODO 与 威富通订单号必须有一个存在
        map.put("out_trade_no", oldorder.getRecordno().toString());
        //威富通订单号
        map.put("transaction_id", oldorder.getTransactionId().toString());
        map.put("out_refund_no", refundObj.getRecordno());//商户退款单号
        BigDecimal totalFee = oldorder.getAmount().multiply(BigDecimal.valueOf(100));
        map.put("total_fee", Utils.round(totalFee, 0).toString());//总金额
        BigDecimal refundFee = refundObj.getAmount().multiply(BigDecimal.valueOf(100));
        map.put("refund_fee", Utils.round(refundFee, 0).toString());//退款金额
        map.put("op_user_id", payChannel.getPayChannelNo());//操作员帐号,默认为商户号
        map.put("nonce_str", RandomStringUtils.getRandomStringByLength(32));
        map.put("refund_channel", "ORIGINAL");
        String strtosign = MapUtils.formatUrlMap(map, false, false);
        String signstr = MD5.sign(strtosign, "&key=" + payChannel.getPayKey(), "utf-8");
        map.put("sign", signstr);
        Param param = Param.create();
        param.putAll(map);
        // 退款接口
        try {
            //今日交易金额
            Map<String, Object> mapDatetrade = new HashMap<>();
            mapDatetrade.put("openid", openid);
            BigDecimal todaySumAmount = tradeRecordService.findTodaySumAmount(mapDatetrade);
            if (todaySumAmount == null) {
                todaySumAmount = BigDecimal.valueOf(0);
            }
            if (oldorder.getAmount().compareTo(todaySumAmount) == 1) { //结果是:-1 小于,0 等于,1 大于
                logger.error("当日交易金额小于退款金额，无法进行退款处理" + openid);
                return R.error("当日交易金额小于退款金额，无法进行退款处理");
            }

            refundObj.setLaunchMode(oldorder.getLaunchMode());
            payorderService.save(refundObj);
            gateway.url = "https://pay.swiftpass.cn/pay/gateway";
            Param resultparam = gateway.post(param);
            System.out.println(resultparam.toString());
            String status = resultparam.get("status");
            if (status.equals("0")) { // 成功
                String result_code = resultparam.get("result_code");// 业务成功结果
                if (result_code.equals("0")) {
                    if (refundObj.getRecordno().equals(resultparam.get("out_refund_no"))) {
                        //平台退款单号  refund_id
                        refundObj.setRefundId(resultparam.get("refund_id"));//平台退款单号
                        refundObj.setRefundChannel(resultparam.get("refund_channel"));//退款渠道
                        refundObj.setPayResult(Integer.valueOf(result_code));
                        refundObj.setStatus(Constant.STATUS_PROCESSING);//退款处理中；
                        payorderService.update(refundObj);
                    }
                } else {
                    refundObj.setRemark(resultparam.get("err_msg"));
                    payorderService.update(refundObj);
                    return R.error(refundObj.getRemark());
                }
            } else {
                refundObj.setRemark(resultparam.get("message"));
                payorderService.update(refundObj);
                return R.error(refundObj.getRemark());
            }
        } catch (Exception e) {
            logger.error("银行通讯失败", e);
            refundObj.setRemark("银行通讯失败");
            payorderService.update(refundObj);
            return R.error(refundObj.getRemark());
        }
        return R.ok();
    }

    /**
     * 重新发起退款交易
     * http://www.***.cn/wechat/payorder/againRefund?merchantNo=88888889
     * 原订单id
     * 订单支付金额
     * 退款订单号
     */
    @ResponseBody
    @RequestMapping("/againRefund")
    public R againRefund(@RequestParam String id) {
        PayorderEntity oldorder = payorderService.queryObject(id);//退款订单
        if (oldorder == null || StringUtil.isEmpty(oldorder.getRecordno())) {
            return R.error("退款订单信息错误");
        }
        PayorderEntity payorder = payorderService.queryByOderNo(oldorder.getOrderid());///订单
        if (payorder == null || StringUtil.isEmpty(payorder.getRecordno())) {
            return R.error("订单信息错误");
        }

        ///查询下商户收款参数信息
        Map<String, Object> mapPayChannel = new HashMap<String, Object>();
        mapPayChannel.put("merchantNo", oldorder.getBusid());
        mapPayChannel.put("payState", Constant.Status.ENABLE.getValue());//状态 0、删除 1、启用 2、禁用
        if (oldorder.getResource() != null && Constant.Resource.RESOURCE_WX.getValue().equals(oldorder.getResource())) {//获取：来源（0 微信、1 支付宝）
            mapPayChannel.put("payType", Constant.PayType.PAY_WX.getValue());//微信
        } else if (oldorder.getResource() != null && Constant.Resource.RESOURCE_ZFB.getValue().equals(oldorder.getResource())) {
            mapPayChannel.put("payType", Constant.PayType.PAY_ZFB.getValue());//支付宝
        } else {
            return R.error("商户渠道参数错误");
        }
        PayChannelEntity payChannel = payChannelService.queryPayBymerchantNo(mapPayChannel);
        if (payChannel == null || StringUtil.isEmpty(payChannel.getPayChannelNo()) || StringUtil.isEmpty(payChannel.getPayKey())) {
            return R.error("商户渠道参数错误");
        }

        Map<String, String> map = new HashMap<String, String>();
        map.put("service", "unified.trade.refund");
        map.put("version", "2.0");
        map.put("charset", "UTF-8");
        map.put("sign_type", "MD5");
        map.put("mch_id", payChannel.getPayChannelNo());
        //商户订单号  -TODO 与 威富通订单号必须有一个存在
        map.put("out_trade_no", oldorder.getOrderid().toString());
        //威富通订单号
        map.put("transaction_id", oldorder.getOrderid().toString());
        map.put("out_refund_no", oldorder.getRecordno());//商户退款单号
        BigDecimal totalFee = payorder.getAmount().multiply(BigDecimal.valueOf(100));
        map.put("total_fee", Utils.round(totalFee, 0).toString());//总金额
        BigDecimal refundFee = oldorder.getAmount().multiply(BigDecimal.valueOf(100));
        map.put("refund_fee", Utils.round(refundFee, 0).toString());//退款金额
        map.put("op_user_id", payChannel.getPayChannelNo());//操作员帐号,默认为商户号
        //map.put("op_user_id", payorder.getBusid().toString());////正式环境启用  -  操作员帐号,默认为商户号
        map.put("nonce_str", RandomStringUtils.getRandomStringByLength(32));
        map.put("refund_channel", "ORIGINAL");
        String strtosign = MapUtils.formatUrlMap(map, false, false);
        String signstr = MD5.sign(strtosign, "&key=" + payChannel.getPayKey(), "utf-8");
        map.put("sign", signstr);
        Param param = Param.create();
        param.putAll(map);
        // 退款接口
        gateway.url = "https://pay.swiftpass.cn/pay/gateway";
        Param resultparam = gateway.post(param);
        System.out.println(resultparam.toString());
        String status = resultparam.get("status");
        if (status.equals("0")) { // 成功
            String result_code = resultparam.get("result_code");// 业务成功结果
            if (result_code.equals("0")) {
                if (oldorder.getRecordno().equals(resultparam.get("out_refund_no"))) {
                    //平台退款单号  refund_id
                    oldorder.setRefundId(resultparam.get("refund_id"));//平台退款单号
                    oldorder.setRefundChannel(resultparam.get("refund_channel"));//退款渠道
                    oldorder.setPayResult(Integer.valueOf(result_code));
                    oldorder.setStatus(Constant.STATUS_PROCESSING);//退款处理中；
                    payorderService.update(oldorder);
                }
            } else {
                oldorder.setRemark(resultparam.get("err_msg"));
                payorderService.update(oldorder);
                return R.error(oldorder.getRemark());
            }
        } else {
            oldorder.setRemark(resultparam.get("message"));
            payorderService.update(oldorder);
            return R.error(oldorder.getRemark());
        }
        return R.ok();
    }


    /**
     * 查询退款状态
     * 定时器来处理  查询订单交易状态
     * http://www.***.cn/wechat/payorder/queryRefundStart?id=20170913110806232
     */
    @ResponseBody
    @RequestMapping("/queryRefundStart")
    public R queryRefundStart(@RequestParam String id) {
        // 退款订单信息
        PayorderEntity oldorder = payorderService.queryObject(id);
        if (oldorder == null || StringUtil.isEmpty(oldorder.getBusid()) || StringUtil.isEmpty(oldorder.getResource())) {
            return R.error("退款订单信息错误");
        }
        ///查询下商户收款参数信息
        Map<String, Object> mapPayChannel = new HashMap<String, Object>();
        mapPayChannel.put("merchantNo", oldorder.getBusid());
        mapPayChannel.put("payState", Constant.Status.ENABLE.getValue());//状态 0、删除 1、启用 2、禁用
        if (oldorder.getResource() != null && Constant.Resource.RESOURCE_WX.getValue().equals(oldorder.getResource())) {//获取：来源（0 微信、1 支付宝）
            mapPayChannel.put("payType", Constant.PayType.PAY_WX.getValue());//微信
        } else if (oldorder.getResource() != null && Constant.Resource.RESOURCE_ZFB.getValue().equals(oldorder.getResource())) {
            mapPayChannel.put("payType", Constant.PayType.PAY_ZFB.getValue());//支付宝
        } else {
            return R.error("商户渠道参数错误");
        }
        PayChannelEntity payChannel = payChannelService.queryPayBymerchantNo(mapPayChannel);
        if (payChannel == null || StringUtil.isEmpty(payChannel.getPayChannelNo()) || StringUtil.isEmpty(payChannel.getPayKey())) {
            return R.error("商户渠道参数错误");
        }

        Map<String, String> map = new HashMap<String, String>();
        map.put("service", "unified.trade.refundquery");
        map.put("version", "2.0");
        map.put("charset", "UTF-8");
        map.put("sign_type", "MD5");
        map.put("mch_id", payChannel.getPayChannelNo());
        //商户订单号  -TODO 与 威富通订单号必须有一个存在
        map.put("refund_id", oldorder.getRefundId());//平台退款单号
        map.put("out_refund_no", oldorder.getRecordno());//商户退款单号
        //威富通订单号
        map.put("transaction_id", oldorder.getOrderid().toString());//平台订单号
        map.put("out_trade_no", oldorder.getOrderid().toString());//商户订单号
        map.put("nonce_str", RandomStringUtils.getRandomStringByLength(32));
        map.put("refund_channel", "ORIGINAL");
        String strtosign = MapUtils.formatUrlMap(map, false, false);
        String signstr = MD5.sign(strtosign, "&key=" + payChannel.getPayKey(), "utf-8");
        map.put("sign", signstr);
        Param param = Param.create();
        param.putAll(map);
        // 退款接口
        gateway.url = "https://pay.swiftpass.cn/pay/gateway";
        Param resultparam = gateway.post(param);
        System.out.println(resultparam.toString());
        String status = resultparam.get("status");
        String msg = "";
        if (status.equals("0")) { // 成功
            String result_code = resultparam.get("result_code");// 业务成功结果
            if (result_code.equals("0")) {
                String refund_count = resultparam.get("refund_count");//退款记录数
                Integer refundCount = Integer.valueOf(StringUtil.isNotEmptyValue(refund_count, 0).toString());
                for (int i = 0; i < refundCount; i++) {
                    PayorderEntity payorder = new PayorderEntity();
                    String outRefundNo = resultparam.get("out_refund_no_" + i);//商户退款单号
                    String refundId = resultparam.get("refund_id_" + i);//平台退款单号
                    payorder.setRefundTime(resultparam.get("refund_time_" + i));//退款时间
                    payorder.setRecordno(outRefundNo);
                    payorder.setRefundId(refundId);
                    String refundStatus = resultparam.get("refund_status_" + i);//退款状态
                    if ("SUCCESS".equals(refundStatus)) {
                        msg = "退款成功";
                        payorder.setStatus(Constant.STATUS_YTK);// 已退款
                    } else if ("FAIL".equals(refundStatus)) {
                        msg = "退款失败";
                        payorder.setStatus(Constant.STATUS_WZ);
                    } else if ("PROCESSING".equals(refundStatus)) {
                        msg = "退款处理中";
                        payorder.setStatus(Constant.STATUS_PROCESSING);
                    } else if ("NOTSURE".equals(refundStatus)) {
                        msg = "未确定， 需要商户原退款单号重新发起";
                        payorder.setStatus(Constant.STATUS_NOTSURE);
                    } else if ("CHANGE".equals(refundStatus)) {
                        msg = "转入代发，退款到银行发现用户的卡作废或者冻结了，导致原路退款银行卡失败，资金回流到商户的现金帐号，需要商户人工干预，通过线下或者平台转账的方式进行退款.";
                        payorder.setStatus(Constant.STATUS_CHANGE);
                    }
                    payorderService.updateRefundStart(payorder);
                }
            } else {
                msg = resultparam.get("err_msg");//
            }
        }
        return R.ok(msg);
    }

    /**
     * 关闭订单
     * 暂时没使用
     */
    @IgnoreAuth
    @RequestMapping(value = "/closequery", method = RequestMethod.POST)
    public R closequery(@RequestBody PayorderEntity payorder) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("service", "unified.micropay.reverse");
        map.put("mch_id", payorder.getBusid().toString());
        map.put("out_trade_no", payorder.getRecordno());
        String strtosign = MapUtils.formatUrlMap(map, false, false);
        String signstr = MD5.sign(strtosign, "&key=9d101c97133837e13dde2d32a5054abb", "utf-8");

        map.put("nonce_str", RandomStringUtils.getRandomStringByLength(32));
        map.put("sign", signstr);
        Param param = Param.create();
        param.putAll(map);

        gateway.url = "https://pay.swiftpass.cn/pay/gateway";
        Param resultparam = gateway.post(param);
        String status = resultparam.get("status");
        if (status.equals("0")) {// 成功
            String result_code = resultparam.get("result_code");// 业务成功结果
            if (result_code.equals("0")) {
                // 原有交易订单
                PayorderEntity oldorder = payorderService.queryByOderNo(payorder.getRecordno());
                oldorder.setStatus("4");// 关闭订单
                payorderService.update(oldorder);
            }
        } else {

        }
        return R.ok();
    }


    /**
     * 支付通知结果  存表
     *
     * @param map
     */
    public TPayresultEntity initPayResultNotify(Map<String, Object> map) {
        TPayresultEntity entity = new TPayresultEntity();
        entity.setOpenid(map.get("openid").toString());
        entity.setTradeType(StringUtil.isNotEmptyValue(map.get("trade_type"), "").toString());
        entity.setIsSubscribe(StringUtil.isNotEmptyValue(map.get("is_subscribe"), "").toString());
        entity.setPayResult(StringUtil.isNotEmptyValue(map.get("pay_result"), "").toString());
        //支付结果信息，支付成功时为空
        entity.setPayInfo(StringUtil.isNotEmptyValue(map.get("pay_info"), "").toString());
        entity.setTransactionId(StringUtil.isNotEmptyValue(map.get("transaction_id"), "").toString());
        entity.setOutTransactionId(StringUtil.isNotEmptyValue(map.get("out_transaction_id"), "").toString());
        entity.setSubIsSubscribe(StringUtil.isNotEmptyValue(map.get("sub_is_subscribe"), "").toString());
        entity.setSubAppid(StringUtil.isNotEmptyValue(map.get("sub_appid"), "").toString());
        entity.setSubOpenid(StringUtil.isNotEmptyValue(map.get("sub_openid"), "").toString());
        entity.setOutTradeNo(StringUtil.isNotEmptyValue(map.get("out_trade_no"), "").toString());
        entity.setTotalFee(Integer.valueOf(StringUtil.isNotEmptyValue(map.get("total_fee"), 0).toString()));
        //现金券支付金额<=订单总金额， 订单总金额-现金券金额为现金支付金额
        entity.setCouponFee(Integer.valueOf(StringUtil.isNotEmptyValue(map.get("coupon_fee"), 0).toString()));
        entity.setFeeType(StringUtil.isNotEmptyValue(map.get("fee_type"), "").toString());
        //商家数据包，原样返回
        entity.setAttach(StringUtil.isNotEmptyValue(map.get("attach"), "").toString());
        entity.setBankType(StringUtil.isNotEmptyValue(map.get("bank_type"), "").toString());
        //银行订单号，若为微信支付则为空
        entity.setBankBillno(StringUtil.isNotEmptyValue(map.get("bank_billno"), "").toString());
        entity.setTimeEnd(StringUtil.isNotEmptyValue(map.get("time_end"), "").toString());
        return entity;
    }

    /**
     * 列表
     */
    @RequestMapping("/list")
    @RequiresPermissions("payorder:list")
    public R list(@RequestParam Map<String, Object> params) {
        // 查询列表数据
        Query query = new Query(params);

        List<PayorderEntity> payorderList = payorderService.queryList(query);
        int total = payorderService.queryTotal(query);

        PageUtils pageUtil = new PageUtils(payorderList, total, query.getLimit(), query.getPage());

        return R.ok().put("page", pageUtil);
    }

    ///=========================刷卡支付===============================

    /**
     * 刷卡支付
     *
     * @param payorder
     * @return
     * @ busid   商户ID
     * @ authCode  扫码支付授权码， 设备读取用户展示的条码或者二维码信息
     * @ amount  金额
     */
    @RequestMapping(value = "/savePayCard", method = RequestMethod.POST)
    @ResponseBody
    @IgnoreAuth
    public R savePayCard(@RequestBody PayorderEntity payorder) {
        if (StringUtil.isBlank(payorder.getBusid()) || StringUtil.isEmpty(payorder.getAuthCode()) || StringUtil.isEmpty(payorder.getAmount())) {
            return R.error("支付请求数据错误");
        }
        logger.info("getBusid()=======:" + payorder.getBusid() + "===getResource()=======:" + payorder.getResource() + "-------payremark=" + payorder.getPayremark() + "-------openid=" + payorder.getOpenid());
        MerchantInfoEntity merchant = merchantService.queryObject(payorder.getBusid());
        if (merchant == null || StringUtil.isEmpty(merchant.getMerchantNo()) || StringUtil.isEmpty(merchant.getPayKey())) {
            return R.error("商户资料获取失败");
        }
        payorder.setRecordno(DefaultSequenceManager.get().next(BizSequenceType.TRANSQ));//订单号
        payorder.setOrderdate(new Date());
        payorder.setTimeoutdate(new Date(System.currentTimeMillis() + 300000));// 订单超时5分钟
        payorder.setWxOpenid(payorder.getOpenid());
        payorder.setPayResult(Constant.PAY_RESULT_ERROR);
        payorder.setMchCreateIp(IPUtils.getIpAddr(request));
        payorder.setResource(String.valueOf(Constant.PayType.PAY_SKZF.getValue()));
        // 支付接口地址
        try {
            //查询支付信息
            Map<String, Object> mapPayChannel = new HashMap<String, Object>();
            mapPayChannel.put("merchantNo", payorder.getBusid());//商户编号
            mapPayChannel.put("payState", Constant.Status.ENABLE.getValue());//状态 0、删除 1、启用 2、禁用
            mapPayChannel.put("payType", Constant.PayType.PAY_ZFB.getValue());//支付类型(统一刷卡支付)
            //mapPayChannel.put("payType", Constant.PayType.PAY_SKZF.getValue());//支付类型(统一刷卡支付)
            PayChannelEntity payChannel = payChannelService.queryPayBymerchantNo(mapPayChannel);
            if (payChannel == null || StringUtil.isEmpty(payChannel.getPayChannelNo()) || StringUtil.isEmpty(payChannel.getPayRate()) || StringUtil.isEmpty(payChannel.getPayKey())) {
                return R.error("商户渠道参数错误");
            } else {
                //单笔累计限额
                if (StringUtil.isNotEmpty(payChannel.getMaxTransactionMoney())) {
                    if (payorder.getAmount().compareTo(payChannel.getMaxTransactionMoney()) == 1) { //结果是:-1 小于,0 等于,1 大于
                        return R.error("已超出商户号设置的最大限额【" + payChannel.getMaxTransactionMoney() + "】");
                    }
                }
            }
            //日累计限额
            //查询当前商户渠道已累计退/收款金额
            Map<String, Object> payMap = new HashMap<>();
            payMap.put("busId", payorder.getBusid());
            payMap.put("paychannelId", payChannel.getPayChannelId());
            BigDecimal sumPayorder = payorderService.findTdSumAmountByPayChannelId(payMap);
            if (sumPayorder != null && StringUtil.isNotEmpty(sumPayorder)) {
                if (sumPayorder.compareTo(payChannel.getDayMaxMoney()) != -1) { //【日累计限额（元/笔）】结果是:-1 小于,0 等于,1 大于
                    return R.error("已超出商户号设置的日累计限额【" + payChannel.getDayMaxMoney() + "】");
                }
            }
            //签约汇率
            payorder.setPayRate(payChannel.getPayRate());
            //结算金额  金额*签约汇率/100
            BigDecimal serviceCharge = payChannel.getPayRate().multiply(payorder.getAmount()).divide(BigDecimal.valueOf(100));
            payorder.setServiceCharge(serviceCharge);
            BigDecimal settlementAmount = payorder.getAmount().subtract(serviceCharge);
            payorder.setSettlementAmount(settlementAmount);
            payorder.setPaychannelId(payChannel.getPayChannelId());//支付渠道id
            // 1、生成本系统中订单
            return payorderService.savePayOrder(payorder, payChannel);
        } catch (Exception e) {
            logger.error("请求支付接口异常：", e);
            // 异常记录
            payorder.setRemark("请求支付接口异常");
            payorder.setStatus(Constant.STATUS_ERROR);
            payorderService.update(payorder);
            return R.error(payorder.getRemark());
        }
    }


    /**
     * 信息
     */
    @RequestMapping("/info/{id}")
    @RequiresPermissions("payorder:info")
    public R info(@PathVariable("id") String id) {
        PayorderEntity payorder = payorderService.queryObject(id);

        return R.ok().put("payorder", payorder);
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    @RequiresPermissions("payorder:update")
    public R update(@RequestBody PayorderEntity payorder) {
        payorderService.update(payorder);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    @RequiresPermissions("payorder:delete")
    public R delete(@RequestBody String[] ids) {
        payorderService.deleteBatch(ids);
        return R.ok();
    }

}
